#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <dirent.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>

//player
#include "player.h"
#include "interface.h"

//panel parameter
#include "SAT070CP50_1024x600.h"
//#include "SAT070CP50_1024x600.h"

//mi
#include "mi_common.h"
#include "mi_sys.h"
#include "mi_disp.h"
#include "mi_panel.h"
#include "mi_hdmi.h"

#define MAKE_YUYV_VALUE(y,u,v)  ((y) << 24) | ((u) << 16) | ((y) << 8) | (v)
#define YUYV_BLACK              MAKE_YUYV_VALUE(0,128,128)

#define PANEL_MAX_W     1024
#define PANEL_MAX_H     600

#define HDMI_MAX_W      1920
#define HDMI_MAX_H      1080

typedef enum
{
    E_MI_HDMI_OUT_1080P = 0,
    E_MI_HDMI_OUT_4K,
    E_MI_HDMI_OUT_720P,
    E_MI_HDMI_OUT_MAX,
} HDMI_Out_e;

#if ENABLE_HDMI
static MI_S32 hdmi_callback_impl(MI_HDMI_DeviceId_e eHdmi, MI_HDMI_EventType_e Event, void *pEventParam, void *pUsrParam)
{
    switch (Event)
    {
        case E_MI_HDMI_EVENT_HOTPLUG:
            printf("E_MI_HDMI_EVENT_HOTPLUG.\n");
            break;
        case E_MI_HDMI_EVENT_NO_PLUG:
            printf("E_MI_HDMI_EVENT_NO_PLUG.\n");
            break;
        default:
            printf("Unsupport event.\n");
            break;
    }

    return MI_SUCCESS;
}
#endif

int sstar_panel_init(MI_DISP_Interface_e eType, HDMI_Out_e outMode)
{
    MI_DISP_PubAttr_t stDispPubAttr;
    MI_DISP_InputPortAttr_t stInputPortAttr;

#if (!ENABLE_HDMI)
    MI_PANEL_LinkType_e eLinkType;

    if (eType == E_MI_DISP_INTF_LCD)
    {
        stDispPubAttr.stSyncInfo.u16Vact       = stPanelParam.u16Height;
        stDispPubAttr.stSyncInfo.u16Vbb        = stPanelParam.u16VSyncBackPorch;
        stDispPubAttr.stSyncInfo.u16Vfb        = stPanelParam.u16VTotal - (stPanelParam.u16VSyncWidth +
                                                 stPanelParam.u16Height + stPanelParam.u16VSyncBackPorch);
        stDispPubAttr.stSyncInfo.u16Hact       = stPanelParam.u16Width;
        stDispPubAttr.stSyncInfo.u16Hbb        = stPanelParam.u16HSyncBackPorch;
        stDispPubAttr.stSyncInfo.u16Hfb        = stPanelParam.u16HTotal - (stPanelParam.u16HSyncWidth +
                                                 stPanelParam.u16Width + stPanelParam.u16HSyncBackPorch);
        stDispPubAttr.stSyncInfo.u16Bvact      = 0;
        stDispPubAttr.stSyncInfo.u16Bvbb       = 0;
        stDispPubAttr.stSyncInfo.u16Bvfb       = 0;
        stDispPubAttr.stSyncInfo.u16Hpw        = stPanelParam.u16HSyncWidth;
        stDispPubAttr.stSyncInfo.u16Vpw        = stPanelParam.u16VSyncWidth;
        stDispPubAttr.stSyncInfo.u32FrameRate  = stPanelParam.u16DCLK * 1000000 / (stPanelParam.u16HTotal * stPanelParam.u16VTotal);
        stDispPubAttr.eIntfSync                = E_MI_DISP_OUTPUT_USER;
        stDispPubAttr.eIntfType                = E_MI_DISP_INTF_LCD;
        stDispPubAttr.u32BgColor               = YUYV_BLACK;

        MI_DISP_SetPubAttr(0, &stDispPubAttr);
        MI_DISP_Enable(0);
        MI_DISP_BindVideoLayer(0, 0);
        MI_DISP_EnableVideoLayer(0);

        MI_DISP_GetInputPortAttr(0, 0, &stInputPortAttr);
        stInputPortAttr.u16SrcWidth         = PANEL_MAX_W;
        stInputPortAttr.u16SrcHeight        = PANEL_MAX_H;
        stInputPortAttr.stDispWin.u16X      = 0;
        stInputPortAttr.stDispWin.u16Y      = 0;
        stInputPortAttr.stDispWin.u16Width  = PANEL_MAX_W;
        stInputPortAttr.stDispWin.u16Height = PANEL_MAX_H;

        MI_DISP_SetInputPortAttr(0, 0, &stInputPortAttr);
        MI_DISP_EnableInputPort(0, 0);
        MI_DISP_SetInputPortSyncMode(0, 0, E_MI_DISP_SYNC_MODE_FREE_RUN);

        eLinkType = E_MI_PNL_LINK_TTL;
        MI_PANEL_Init(eLinkType);
        MI_PANEL_SetPanelParam(&stPanelParam);
    }
#else
    if (eType == E_MI_DISP_INTF_HDMI)
    {
        MI_HDMI_InitParam_t stInitParam;
        MI_HDMI_Attr_t stAttr;
        MI_DISP_VideoLayerAttr_t stLayerAttr;

        stInitParam.pCallBackArgs = NULL;
        stInitParam.pfnHdmiEventCallback = hdmi_callback_impl;
        MI_HDMI_Init(&stInitParam);
        MI_HDMI_Open(E_MI_HDMI_ID_0);

        memset(&stAttr, 0, sizeof(MI_HDMI_Attr_t));
        stAttr.stEnInfoFrame.bEnableAudInfoFrame= FALSE;
        stAttr.stEnInfoFrame.bEnableAviInfoFrame= FALSE;
        stAttr.stEnInfoFrame.bEnableSpdInfoFrame= FALSE;
        stAttr.stAudioAttr.bEnableAudio         = TRUE;
        stAttr.stAudioAttr.bIsMultiChannel      = 0;//hdmi ouptut audio layout
        stAttr.stAudioAttr.eBitDepth            = E_MI_HDMI_BIT_DEPTH_16;
        stAttr.stAudioAttr.eCodeType            = E_MI_HDMI_ACODE_PCM;
        stAttr.stAudioAttr.eSampleRate          = E_MI_HDMI_AUDIO_SAMPLERATE_48K;
        stAttr.stVideoAttr.bEnableVideo         = TRUE;
        stAttr.stVideoAttr.eColorType           = E_MI_HDMI_COLOR_TYPE_RGB444;//default color type
        if(outMode == E_MI_HDMI_OUT_4K) {   
            stAttr.stVideoAttr.eDeepColorMode       = E_MI_HDMI_DEEP_COLOR_24BIT;
            stAttr.stVideoAttr.eTimingType          = E_MI_HDMI_TIMING_4K2K_30P; //bill
        } else if(outMode == E_MI_HDMI_OUT_720P) {
            stAttr.stVideoAttr.eDeepColorMode       = E_MI_HDMI_DEEP_COLOR_24BIT;
            stAttr.stVideoAttr.eTimingType          = E_MI_HDMI_TIMING_720_60P; 
        } else {
            stAttr.stVideoAttr.eDeepColorMode       = E_MI_HDMI_DEEP_COLOR_MAX;
            stAttr.stVideoAttr.eTimingType          = E_MI_HDMI_TIMING_1080_60P;
        }
        stAttr.stVideoAttr.eOutputMode          = E_MI_HDMI_OUTPUT_MODE_HDMI;
        MI_HDMI_SetAttr(E_MI_HDMI_ID_0, &stAttr);
        MI_HDMI_Start(E_MI_HDMI_ID_0);
        stDispPubAttr.u32BgColor                = YUYV_BLACK;
        stDispPubAttr.eIntfType                 = E_MI_DISP_INTF_HDMI;
        if(outMode == E_MI_HDMI_OUT_4K) {
            stDispPubAttr.eIntfSync                 = E_MI_DISP_OUTPUT_3840x2160_30;
        } else if(outMode == E_MI_HDMI_OUT_720P) {
            stDispPubAttr.eIntfSync                 = E_MI_DISP_OUTPUT_720P60;
        } else {
            stDispPubAttr.eIntfSync                 = E_MI_DISP_OUTPUT_1080P60;
        }
        MI_DISP_SetPubAttr(0, &stDispPubAttr);
        MI_DISP_Enable(0);
        MI_DISP_BindVideoLayer(0, 0);
        memset(&stLayerAttr, 0, sizeof(stLayerAttr));
        stLayerAttr.stVidLayerSize.u16Width     = HDMI_MAX_W;
        stLayerAttr.stVidLayerSize.u16Height    = HDMI_MAX_H;
        stLayerAttr.ePixFormat                  = E_MI_SYS_PIXEL_FRAME_YUV_MST_420;
        stLayerAttr.stVidLayerDispWin.u16X      = 0;
        stLayerAttr.stVidLayerDispWin.u16Y      = 0;
        if(outMode == E_MI_HDMI_OUT_4K) {
            stLayerAttr.stVidLayerDispWin.u16Width  = 3840;
            stLayerAttr.stVidLayerDispWin.u16Height = 2160;
        } else if(outMode == E_MI_HDMI_OUT_720P) {
            stLayerAttr.stVidLayerDispWin.u16Width  = 1280;
            stLayerAttr.stVidLayerDispWin.u16Height = 720;
        }else{
            stLayerAttr.stVidLayerDispWin.u16Width  = HDMI_MAX_W;
            stLayerAttr.stVidLayerDispWin.u16Height = HDMI_MAX_H;
        }
        MI_DISP_SetVideoLayerAttr(0, &stLayerAttr);
        MI_DISP_EnableVideoLayer(0);

        MI_DISP_GetInputPortAttr(0, 0, &stInputPortAttr);
        stInputPortAttr.u16SrcWidth         = HDMI_MAX_W;
        stInputPortAttr.u16SrcHeight        = HDMI_MAX_H;
        stInputPortAttr.stDispWin.u16X      = 0;
        stInputPortAttr.stDispWin.u16Y      = 0;
        stInputPortAttr.stDispWin.u16Width  = HDMI_MAX_W;
        stInputPortAttr.stDispWin.u16Height = HDMI_MAX_H;

        MI_DISP_SetInputPortAttr(0, 0, &stInputPortAttr);
        MI_DISP_EnableInputPort(0, 0);
        MI_DISP_SetInputPortSyncMode(0, 0, E_MI_DISP_SYNC_MODE_FREE_RUN);
    }
#endif

    return MI_SUCCESS;
}

int sstar_panel_deinit(MI_DISP_Interface_e eType)
{
    MI_DISP_DisableInputPort(0, 0);
    MI_DISP_DisableVideoLayer(0);
    MI_DISP_UnBindVideoLayer(0, 0);
    MI_DISP_Disable(0);

    switch(eType)
    {
#if ENABLE_HDMI
        case E_MI_DISP_INTF_HDMI:
            MI_HDMI_Stop(E_MI_HDMI_ID_0);
            MI_HDMI_Close(E_MI_HDMI_ID_0);
            MI_HDMI_DeInit();
        break;
#else
        case E_MI_DISP_INTF_LCD:
            MI_PANEL_DeInit();
        break;
#endif

        case E_MI_DISP_INTF_VGA:
        break;

        default: break;
    }

    return MI_SUCCESS;
}

void sstar_getpanel_wh(int *width, int *height)
{
#if (!ENABLE_HDMI)
    MI_DISP_PubAttr_t stPubAttr;
    MI_DISP_GetPubAttr(0,&stPubAttr);
    *width = stPubAttr.stSyncInfo.u16Hact;
    *height = stPubAttr.stSyncInfo.u16Vact;
#else
    MI_DISP_VideoLayerAttr_t stLayerAttr;
    MI_DISP_GetVideoLayerAttr(0, &stLayerAttr);
    *width = stLayerAttr.stVidLayerDispWin.u16Width;
    *height = stLayerAttr.stVidLayerDispWin.u16Height;
#endif
    printf("sstar_getpanel_wh = [%d %d]\n", *width, *height);
}

int sstar_panel_setluma(uint32_t luma)
{
    if (luma > 100 || luma < 0) {
        printf("parameter error, luma value range [0~100]\n");
        return -1;
    }
#if (!ENABLE_HDMI)
    MI_DISP_LcdParam_t stLcdParam;

    MI_DISP_GetLcdParam(0, &stLcdParam);
    printf("get panel luma [%u], set value [%u]\n", stLcdParam.stCsc.u32Luma, luma);

    stLcdParam.stCsc.u32Luma = luma;
    MI_DISP_SetLcdParam(0, &stLcdParam);
#else
    MI_DISP_HdmiParam_t stHdmiParam;

    MI_DISP_GetHdmiParam(0, &stHdmiParam);
    printf("get hdmi luma [%u], set value [%u]\n", stHdmiParam.stCsc.u32Luma, luma);

    stHdmiParam.stCsc.u32Luma = luma;
    MI_DISP_SetHdmiParam(0, &stHdmiParam);
#endif
    return 0;
}

int sstar_panel_setcontrast(uint32_t contrast)
{
    if (contrast > 100 || contrast < 0) {
        printf("parameter error, luma value range [0~100]\n");
        return -1;
    }
#if (!ENABLE_HDMI)
    MI_DISP_LcdParam_t stLcdParam;

    MI_DISP_GetLcdParam(0, &stLcdParam);
    printf("get panel contrast [%u], set value [%u]\n", stLcdParam.stCsc.u32Contrast, contrast);

    stLcdParam.stCsc.u32Contrast = contrast;
    MI_DISP_SetLcdParam(0, &stLcdParam);
#else
    MI_DISP_HdmiParam_t stHdmiParam;

    MI_DISP_GetHdmiParam(0, &stHdmiParam);
    printf("get hdmi contrast [%u], set value [%u]\n", stHdmiParam.stCsc.u32Contrast, contrast);

    stHdmiParam.stCsc.u32Luma = contrast;
    MI_DISP_SetHdmiParam(0, &stHdmiParam);
#endif
    return 0;
}


int sstar_sys_init(void)
{
    MI_SYS_Version_t stVersion;
    MI_U64 u64Pts = 0;
    MI_SYS_Init();
    memset(&stVersion, 0x0, sizeof(MI_SYS_Version_t));
    MI_SYS_GetVersion(&stVersion);
    MI_SYS_GetCurPts(&u64Pts);
    u64Pts = 0xF1237890F1237890;
    MI_SYS_InitPtsBase(u64Pts);
    u64Pts = 0xE1237890E1237890;
    MI_SYS_SyncPts(u64Pts);
    return MI_SUCCESS;
}

int sstar_sys_deinit(void)
{
    MI_SYS_Exit();
    return MI_SUCCESS;
}

/*******************************************************************************************/

#define TYPE_LIST_NUM   26
#define FILE_NUM_MAX    256

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

static int width, height;
static bool b_exit = false;

typedef struct {
    char f_path[128];
    char f_name[FILE_NUM_MAX][128];
    int  f_index;
    int  f_num;
} file_tree_t;

struct player_t {
    char file[256];
    char *path;
    int  mode;
    int  width, height;
    int  flag;
    bool status;
    file_tree_t ftree;
};

static char *type_filter[TYPE_LIST_NUM] = {
    ".mp4",
    ".avi",
    ".wav",
    ".flv",
    ".mkv",
    ".mp3",
    ".mov",
    ".rm",
    ".rmvb",
    ".wmv",
    ".vob",
    ".mpg",
    ".mpeg",
    ".m4v",
    ".ts",
    ".m4a",
    ".mka",
    ".ape",
    ".adts",
    ".asf",
    ".wma",
    ".webm",
    ".divx",
    ".ogm",
    ".trp",
    ".tp"
};

static int create_file_tree(const char *path, file_tree_t *tree, char **filter)
{
    DIR *dir;
    struct dirent *entry;
    int i;

    if (!tree || !path)
    {
        fprintf(stderr, "path or tree is null!\n");
        return -1;
    }

    memset(tree->f_path, '\0', sizeof(tree->f_path));
    memcpy(tree->f_path, path, strlen(path));

    if ((dir = opendir(tree->f_path)) == NULL) {
        fprintf(stderr, "can't open directory %s\n", tree->f_path);
        return -1;
    }

    while ((entry = readdir(dir)) != NULL) 
    {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        {
            continue;
        }
        else
        {
            for(i = 0; i < TYPE_LIST_NUM; i ++)
            {
                int filter_len = strlen(filter[i]);
                int name_len = strlen(entry->d_name);
                if (name_len > filter_len)
                {
                    if (!strcasecmp (entry->d_name + (name_len - filter_len), filter[i]))
                    {
                        memset(tree->f_name[tree->f_num], '\0', sizeof(tree->f_name[tree->f_num]));
                        memcpy(tree->f_name[tree->f_num], entry->d_name, name_len);
                        tree->f_num ++;
                        //printf("type: %d, file[%d] name: %s\n", entry->d_type, tree->f_num, entry->d_name);
                        break;
                    }
                }
            }
        }

        if (tree->f_num >= FILE_NUM_MAX)
        {
            printf("files num are over %d\n", FILE_NUM_MAX);
            break;
        }
    }

    closedir(dir);

    if (tree->f_num > 0)
    {
        printf("had find %d files in %s.\n", tree->f_num, path);
    }
    else
    {
        printf("no find valid files in %s.\n", path);
        return -1;
    }

    return 0;
}

static int get_next_filename(file_tree_t *tree, char *filename)
{
    if (!tree || !filename)
    {
        fprintf(stderr, "tree or filename is null!\n");
        return -1;
    }

    tree->f_index ++;
    if (tree->f_index >= tree->f_num)
    {
        tree->f_index = 0;
    }

    memset(filename, '\0', 256);
    sprintf(filename, "%s/%s", tree->f_path, tree->f_name[tree->f_index]);

    printf("get_next_filename: %s\n", filename);

    return 0;
}

static int get_prev_filename(file_tree_t *tree, char *filename)
{
    if (!tree || !filename)
    {
        fprintf(stderr, "tree or filename is null!\n");
        return -1;
    }

    tree->f_index --;
    if (tree->f_index < 0)
    {
        tree->f_index = tree->f_num - 1;
    }

    memset(filename, '\0', 256);
    sprintf(filename, "%s/%s", tree->f_path, tree->f_name[tree->f_index]);

    printf("get_prev_filename: %s\n", filename);

    return 0;
}

static void * mm_player_thread(void *args)
{
    int ret;
    struct player_t *is = (struct player_t *)args;

    while (!b_exit)
    {
        if (is->status)
        {
            ret = mm_player_get_status();
            if (ret > AV_PLAY_PAUSE)
            {
                printf("play %s error!\n", is->file);
                if (!is->flag)
                {
                    b_exit = true;
                }
                else
                {
                    mm_player_close();
                    is->status = false;
                    sleep(1);
                    goto replay;
                }
            }
            else if (ret == AV_PLAY_COMPLETE)
            {
                switch (is->mode)
                {
                    case 0:
                    break;

                    case 1:
                        mm_player_close();
                        is->status = false;
                        sleep(1);
                        ret = mm_player_open(is->file, 0, 0, is->width, is->height);
                        if (ret < 0) {
                            mm_player_close();
                            printf("mm_player_open failed, please enter 'q' to exit!\n");
                        }
                        is->status = true;
                    break;

                    case 2:
                        mm_player_close();
                        is->status = false;
                        sleep(1);
replay:
                        get_next_filename(&(is->ftree), is->file);
                        printf("try to play %s ...\n", is->file);
                        ret = mm_player_open(is->file, 0, 0, is->width, is->height);
                        if (ret < 0) {
                            mm_player_close();
                            printf("mm_player_open failed!\n");
                            goto replay;
                        }
                        is->status = true;
                    break;

                    default :
                        printf("invalid mode!\n");
                    break;
                }
            }
        }
        av_usleep(50 * 1000);
    }

    return NULL;
}

void signal_handler_fun(int signum) {
    printf("catch signal [%d]\n", signum);
    b_exit = true;
}

int main(int argc, char *argv[])
{
    char cmd;
    int ret, volumn = 0;
    bool mute = false, win_down = false;
    double duration, position;
    pthread_t mm_thread = 0;
    struct player_t myplay;
    uint32_t luma = 50, contrast = 50;

    memset(&myplay, 0x0, sizeof(struct player_t));

    if (argc < 2)
    {
        printf("input parameter invalid!\n");
        printf("eg: ./ssplayer file test.mp4 or ./ssplayer path /mnt/video\n");
        return -1;
    }
    else
    {
        if (!strcmp(argv[1], "path"))
        {
            myplay.flag = 1;
            myplay.path = argv[2];
            ret = create_file_tree(myplay.path, &myplay.ftree, type_filter);
            if (ret != 0)
            {
                printf("create_file_tree failed!\n");
                return -1;
            }
            memset(myplay.file, '\0', sizeof(myplay.file));
            sprintf(myplay.file, "%s/%s", myplay.path, myplay.ftree.f_name[myplay.ftree.f_index]);
            printf("try playing %s ...\n", myplay.file);
        }
        else if (!strcmp(argv[1], "file"))
        {
            myplay.flag = 0;
            memset(myplay.file, '\0', sizeof(myplay.file));
            memcpy(myplay.file, argv[2], strlen(argv[2]));
            printf("try playing %s ...\n", myplay.file);
        }
        else
        {
            printf("unknown args type!\n");
            return -1;
        }
        myplay.mode = 0;
    }

    printf("welcome to test ssplayer!\n");

    signal(SIGINT, signal_handler_fun);

    sstar_sys_init();

    #if ENABLE_HDMI
    sstar_panel_init(E_MI_DISP_INTF_HDMI, 0);
    mm_player_set_opts("audio_device", "", 3);//hdmi audio device is 2/3
    mm_player_set_opts("audio_layout", "", AV_CH_LAYOUT_MONO);//keep the same with hdmi init
    #else
    sstar_panel_init(E_MI_DISP_INTF_LCD, 0);
    mm_player_set_opts("audio_device", "", 0);
    #endif

    sstar_getpanel_wh(&width, &height);
    myplay.width  = width;
    myplay.height = height;

    printf("try playing %s ...\n", myplay.file);

    mm_player_set_opts("video_rotate", "", AV_ROTATE_NONE);
    mm_player_set_opts("video_only", "", 0);
    mm_player_set_opts("video_ratio", "", AV_SCREEN_MODE);
    mm_player_set_opts("enable_scaler", "", 0);
    mm_player_set_opts("resolution", "8294400", 0);

    //call set opts before open
    ret = mm_player_open(myplay.file, 0, 0, width, height);
    if (ret < 0) {
        goto exit;
    }
    mm_player_getduration(&duration);
    myplay.status = true;

    ret = pthread_create(&mm_thread, NULL, mm_player_thread, (void *)&myplay);
    if (ret != 0)
    {
        goto exit;
    }

    b_exit = false;
    while (!b_exit)
    {
        fflush(stdin);
        cmd = getchar();
        switch (cmd) 
        {
            case 's':
                mm_player_open(myplay.file, 0, 0, width, height);
                myplay.status = true;
            break;

            case 't':
                mm_player_close();
                myplay.status = false;
            break;

            case 'f':
                mm_player_getposition(&position);
                position += 5.0;
                position = (position >= duration) ? duration : position;
                mm_player_seek2time(position);
            break;

            case 'b':
                mm_player_getposition(&position);
                position -= 5.0;
                position = (position <= 0) ? 0 : position;
                mm_player_seek2time(position);
            break;

            case 'c':
                mm_player_resume();
            break;

            case 'p':
                mm_player_pause();
            break;

            case 'g': {
                mm_player_getduration(&duration);
            }
            break;

            case 'd': {
                mm_player_getposition(&position);
                printf("play %s in [%.3f]\n", argv[1], position);
            }
            break;

            case 'u':
                mute = !mute;
                mm_player_set_mute(mute);
            break;

            case '+':
                volumn += 5;
                volumn  = (volumn > 100) ? 100 : volumn;
                mm_player_set_volumn(volumn);
            break;

            case '-':
                volumn -= 5;
                volumn  = (volumn < 0) ? 0 : volumn;
                mm_player_set_volumn(volumn);
            break;

            case 'w':
                if (!win_down)
                {
                    mm_player_set_window(0, 0, width / 2, height / 2);
                    win_down = true;
                }
                else
                {
                    mm_player_set_window(0, 0, width, height);
                    win_down = false;
                }
            break;

            case 'm':
                if (myplay.mode == 0) {
                    printf("change to sigle cyclic mode!\n");
                    myplay.mode = 1;
                } else if (myplay.mode == 1) {
                    if (myplay.flag) {
                        printf("change to list cyclic mode!\n");
                        myplay.mode = 2;
                    } else {
                        printf("change to sigle mode!\n");
                        myplay.mode = 0;
                    }
                } else if (myplay.mode == 2) {
                    printf("change to sigle mode!\n");
                    myplay.mode = 0;
                }
            break;

            case 'l':
                luma = (luma >= 100) ? 0 : (luma + 10);
                sstar_panel_setluma(luma);
            break;

            case 'h':
                contrast = (contrast >= 100) ? 0 : (contrast + 10);
                sstar_panel_setcontrast(contrast);
            break;

            case 'n':
                if (myplay.flag)
                {
                    mm_player_close();
                    myplay.status = false;
                    sleep(1);
next:
                    get_next_filename(&(myplay.ftree), myplay.file);
                    printf("try to play %s ...\n", myplay.file);
                    ret = mm_player_open(myplay.file, 0, 0, myplay.width, myplay.height);
                    if (ret < 0) {
                        mm_player_close();
                        printf("mm_player_open failed!\n");
                        goto next;
                    }
                    myplay.status = true;
                }
            break;

            case 'z':
                if (myplay.flag)
                {
                    mm_player_close();
                    myplay.status = false;
                    sleep(1);
prev:
                    get_prev_filename(&(myplay.ftree), myplay.file);
                    printf("try to play %s ...\n", myplay.file);
                    ret = mm_player_open(myplay.file, 0, 0, myplay.width, myplay.height);
                    if (ret < 0) {
                        mm_player_close();
                        printf("mm_player_open failed!\n");
                        goto prev;
                    }
                    myplay.status = true;
                }
            break;

            case 'q':
                b_exit = true;
            break;

            default : break;
        }
        fflush(stdout);
        cmd = '\0';
    }

    if (mm_thread)
        pthread_join(mm_thread, NULL);

exit:
    mm_player_close();

    #if ENABLE_HDMI
    sstar_panel_deinit(E_MI_DISP_INTF_HDMI);
    #else
    sstar_panel_deinit(E_MI_DISP_INTF_LCD);
    #endif
    sstar_sys_deinit();

    return 0;
}


